import * as step from '@flow-step/step-toolkit'
import process from 'process'
import * as fs from 'fs-extra'
import {getParams,IParams} from './params'
import path from 'path'
import {getRule} from './rule'
import {setDependentFiles} from './utils'
import {parseAndUploadReport} from './parse-upload-report'
import {setupJavaAndMaven} from './setupJava'
import {copyDiffFiles} from './copyDiffFiles'

export const IS_LINUX = process.platform === 'linux'
export const IS_X64 = process.arch === 'x64'
async function runStep(): Promise<void> {
    if (!IS_LINUX || !IS_X64) {
        throw new Error('JavaP3CScan only supports Linux/amd64 systems now')
    }
    const params = getParams()

    step.info(`PIPELINE_ID=${params.pipelineID}`)
    step.info(`PIPELINE_NAME=${params.pipelineName}`)
    step.info(`BUILD_NUMBER=${params.buildNumber}`)
    step.info(`WORK_SPACE=${params.workSpace}`)
    step.info(`PROJECT_DIR=${params.projectDir}`)
    step.info(`BUILD_JOB_ID=${params.buildJobID}`)
    step.info(`incrementalScan=${params.incrementalScan}`)
    step.info(`useCustomRule=${params.useCustomRule}`)
    step.info(`subDir=${params.subDir}`)
    step.info(`exclusion=${params.exclusion}`)
    step.info(`qualityGate=${params.redline}`)
    const rule = getRule(params)

    await setupJavaAndMaven()
    await setDependentFiles(params.pluginDir)
    const reportPath = await p3cScan(params,rule)
    await parseAndUploadReport(reportPath,params)
}


//Do p3c scan base on the rule
//Return: report path
export async function p3cScan(params:IParams, rule:string): Promise<string> {

    const copiedScanDir = path.join(params.pluginDir,'codescan','code_origin')
    fs.mkdirSync(copiedScanDir,{ recursive: true })
    //use fs-extra to copy the entire dir
    fs.copySync(params.projectScanDir,copiedScanDir,{overwrite:true})

    // added LANG env variable by pipelinelocale
    process.env.LANG = `${params.pipelineLocale}.UTF-8`
    // exclude files which need to be excluded
    step.info(`java -classpath ${path.join(params.pluginDir,'plugin-base.jar')} com.alibaba.aone.apps.Exclude -p "rdc" -s "${copiedScanDir}" -e "$EXCLUSION"`)
    let exitCode = await step.exec.call('java',['-classpath',path.join(params.pluginDir,'plugin-base.jar'),'com.alibaba.aone.apps.Exclude','-p','rdc','-s', copiedScanDir,'-e',params.exclusion||''])
    if (exitCode !== 0) {
        throw new Error(`failed to run the java command right above, exit code: ${exitCode}`)
    }


    let scanPath:string
    if (!params.incrementalScan){
        step.info(`not use incrementalScan`)
        scanPath = copiedScanDir
    }else{
        step.info(`use incrementalScan`)
        scanPath = path.join(params.pluginDir,'codescan','code')
        fs.mkdirSync(scanPath,{ recursive: true })
        const commitInfoPath = path.join(params.projectDir,'..','commitInfo')
        if(process.env.FLOW_RUNNER_DEBUG){
            const commitInfoData = fs.readFileSync(commitInfoPath,'utf-8')
            step.debug('commitInfo: ' + commitInfoData)
        }
        const diffListPath = path.join(params.pluginDir,'fileList.txt')
        step.info(`${path.join(params.pluginDir,'diff')} -c ${commitInfoPath} -s ${params.projectScanDir} -f java -o ${path.join(params.pluginDir,'diff_result.json')} -l ${diffListPath}`)
        exitCode = await step.exec.call(path.join(params.pluginDir,'diff'),['-c',commitInfoPath,'-s',params.projectScanDir,'-f','java','-o',path.join(params.pluginDir,'diff_result.json'),'-l',diffListPath],{
            listener: {
                stdoutLine: (line: string) => step.info(line),
                stderrLine: (line: string) => step.error(line)
            }
        })
        if (exitCode !== 0) {
            throw new Error(`diff exec failed, exit code: ${exitCode}`)
        }

        if (fs.existsSync(diffListPath)) {
            copyDiffFiles(diffListPath, copiedScanDir, scanPath,params.subDir)
        } else {
            step.info('No Java file changes detected')
        }
    }

    step.info(`execute p3c-pmd`)
    const pmdLanguage = params.language
    step.info(`java -Dfile.encoding=UTF-8 -Dpmd.language=${pmdLanguage} -Duser.language=${params.pipelineLocale} -cp $PLUGIN_DIR/p3c/lib/p3c-pmd.jar net.sourceforge.pmd.PMD -d ${scanPath} -R ${rule} -f xslt --failOnViolation false > ${params.projectScanDir}/index.html`)
    const commandResult = await step.exec.callOutput('java', ['-Dfile.encoding=UTF-8', '-Dpmd.language=' + pmdLanguage, '-Duser.language=' + params.pipelineLocale, '-cp', path.join(params.pluginDir,'p3c','lib','p3c-pmd.jar'), 'net.sourceforge.pmd.PMD', '-d', scanPath, '-R', rule, '-f', 'xslt', '--failOnViolation','false'])
    if (commandResult.exitCode != 0){
        step.error(commandResult.stderrContent)
        throw new Error(`executing p3c-pmd failed`)
    }
    const reportPath = path.join(params.projectScanDir, 'index.html')
    fs.writeFileSync(reportPath, commandResult.stdoutContent, 'utf-8')
    return Promise.resolve(reportPath)
}

runStep()
    .then(function() {
        step.success('run step successfully!')
    })
    .catch(function(err: Error) {
        step.error(err.message)
        process.exit(-1)
    })
